package com.jeasonzhao.model;

import java.lang.reflect.Field;

import com.jeasonzhao.commons.utils.Algorithms;

public class MappedInformation implements java.io.Serializable
{
	private static final long serialVersionUID=1L;
    private Class<?> originalClass = null;
    private String name = null;
    private String title=null;
    private java.util.ArrayList<MappedFieldItem> fields = new java.util.ArrayList<MappedFieldItem>();
    private MappedInformationSourceType sourceType = MappedInformationSourceType.POJO;
    public MappedInformation(Class<?> cls,MappedInformationSourceType type)
        throws ModelException
    {
        if(null == cls)
        {
            throw new ModelConfigurationException("Could not map a instance of " + MappedInformation.class.getName() + " from a null class");
        }
        this.originalClass = cls;
        this.sourceType = type;
    }

    public MappedInformationSourceType getSourceType()
    {
        return sourceType;
    }

    public void setOriginalClass(Class<?> cls)
    {
        this.originalClass = cls;
    }

    public Class<?> getOriginalClass()
    {
        return this.originalClass;
    }

    public MappedInformation setName(String names)
    {
        this.name = names;
        return this;
    }

    public void setTitle(String title)
    {
        this.title = title;
    }

    public String getName()
    {
        return Algorithms.oneOfNotNull(this.name,this.originalClass.getSimpleName());
    }

    public String getTitle()
    {
        return title;
    }

    public MappedInformation addFiledMap(MappedFieldItem ...fields)
        throws ModelException
    {
        if(null == fields)
        {
            return this;
        }
        for(MappedFieldItem item : fields)
        {
            if(item == null)
            {
                continue;
            }
            if(null == this.fields)
            {
                this.fields = new java.util.ArrayList<MappedFieldItem>();
            }
            if(null != item.getField())
            {
                removeFieldMap(item.getField()); //Remove all duplicated items which maybe generated by TYPE annotation and Field annotation
            }
            item.normalize();
            this.fields.add(item);
        }
        return this;
    }

    public void cleanPrimaryKeys()
    {
        for(int n = 0;null != fields && n < fields.size();n++)
        {
            if(null != fields.get(n))
            {
                fields.get(n).setPrimaryKey(false);
            }
        }
    }

    private void removeFieldMap(Field field)
    {
        if(null == fields || null == field)
        {
            return;
        }
        for(int n = 0;n < fields.size();n++)
        {
            if(null == fields.get(n) ||
               (fields.get(n).getField() != null
                && fields.get(n).getField().equals(field)))
            {
                fields.remove(n);
                n--;
            }
        }
    }

    public void clean()
    {
        this.fields = null;
    }

    public MappedFieldItem getFieldMap(String strName)
    {
        if(null == fields)
        {
            return null;
        }
        for(MappedFieldItem item : this.fields)
        {
            if(item.matchs(strName))
            {
                return item;
            }
        }
        return null;
    }

    public MappedFieldItem getFieldMap(Field field)
    {
        if(null == fields)
        {
            return null;
        }
        for(MappedFieldItem item : this.fields)
        {
            if(item.getField().equals(field))
            {
                return item;
            }
        }
        return null;
    }

    public java.util.ArrayList<MappedFieldItem> getMappedItems()
    {
        return this.fields;
    }

    public MappedFieldItem getSinglePrimaryKey()
        throws ModelException
    {
        java.util.ArrayList<MappedFieldItem> ary = this.getPrimaryKeys();
        if(null == ary || ary.size() != 1)
        {
            throw new ModelException("No primary key or more than one primary keys defined in the class " +
                                     this.originalClass.getName());
        }
        else
        {
            return ary.get(0);
        }
    }

    public java.util.ArrayList<MappedFieldItem> getPrimaryKeys()
    {
        if(null == fields)
        {
            return null;
        }
        java.util.ArrayList<MappedFieldItem> ret = new java.util.ArrayList<MappedFieldItem>();
        for(MappedFieldItem item : this.fields)
        {
            if(null != item && item.isPrimaryKey())
            {
                ret.add(item);
            }
        }
        return ret;
    }

    public java.util.ArrayList<MappedFieldItem> getNonPrimaryKeys()
    {
        if(null == fields)
        {
            return null;
        }
        java.util.ArrayList<MappedFieldItem> ret = new java.util.ArrayList<MappedFieldItem>();
        for(MappedFieldItem item : this.fields)
        {
            if(null != item && item.isPrimaryKey() == false)
            {
                ret.add(item);
            }
        }
        return ret;
    }

    public boolean isEmpty()
    {
        return this.fields == null || this.fields.size() < 1;
    }

    public boolean contains(String strFieldName)
    {
        return null != this.getFieldMap(strFieldName);
    }

    public MappedFieldItem getIdField()
    {
        if(null == fields)
        {
            return null;
        }
        for(MappedFieldItem item : this.fields)
        {
            if(null != item
               && item.getAppendix() != null
               && TreeNodeTypes.Id == item.getAppendix().getTreeNodeType())
            {
                return item;
            }
        }
        for(MappedFieldItem item : this.fields)
        {
            if(null != item && "id|code|key|".indexOf(item.getName().toLowerCase() + "|") >= 0)
            {
                return item;
            }
        }
        return null;
    }

    public MappedFieldItem getParentIdField()
    {
        if(null == fields)
        {
            return null;
        }
        for(MappedFieldItem item : this.fields)
        {
            if(null != item
               && item.getAppendix() != null
               && TreeNodeTypes.ParentId == item.getAppendix().getTreeNodeType())
            {
                return item;
            }
        }
        for(MappedFieldItem item : this.fields)
        {
            if(null != item && "parentid|parentcode|parentkey|parent|".indexOf(item.getName().toLowerCase() + "|") >= 0)
            {
                return item;
            }
        }
        return null;
    }

    public MappedFieldItem getNameField()
    {
        if(null == fields)
        {
            return null;
        }
        for(MappedFieldItem item : this.fields)
        {
            if(null != item
               && item.getAppendix() != null
               && TreeNodeTypes.Text == item.getAppendix().getTreeNodeType())
            {
                return item;
            }
        }
        for(MappedFieldItem item : this.fields)
        {
            if(null != item && "name|title|".indexOf(item.getName().toLowerCase() + "|") >= 0)
            {
                return item;
            }
        }
        return null;
    }
    public MappedFieldItem getSortField()
    {
        if(null == fields)
        {
            return null;
        }
        for(MappedFieldItem item : this.fields)
        {
            if(null != item
               && item.getAppendix() != null
               && item.getAppendix().isSortField())
            {
                return item;
            }
        }
        for(MappedFieldItem item : this.fields)
        {
            if(null != item && "sortOrder|sortNumber|sort|sortNo|".toLowerCase().indexOf(item.getName().toLowerCase() + "|") >= 0)
            {
                return item;
            }
        }
        return null;
    }

    public boolean isTreeBean()
    {
        return null!=this.getIdField() && null!=this.getParentIdField();
    }
}
